/*********************************************************************************
 *       Filename:  fork_main.c
 *    Description:  
 *
 *        Version:  1.0.0(2024/12/09 21:29:25)
 *         Author:  Zhang Long <1318085470@qq.com>
 *      ChangeLog:  1, Release initial version on "2024/12/09 21:29:25"
 ********************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <libgen.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sqlite3.h>
#include <sys/epoll.h>
#include <poll.h>
#include <pthread.h>
#include <sys/select.h> 
#include "database.h"
#include "ds18b20.h"
#include "transferdata.h"
#include "localtime.h"
#include "socket.h"
#include "logger.h"
#include "proc.h"

#define MAX_EVENTS 512
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
static inline void print_usage(char *progname)
{
    printf("%s usage: \n", progname);
    printf("-i(--ipaddr): specify server IP address(also not specify, default is all)\n");
    printf("-p(--port):   specify server PORT\n");
	printf("-d(--debug):  specify program running in debug mode\n");
    printf("-h(--help):   print this help information\n");

	printf("\nExample: %s -p 12345 -d\n", progname);

    return ;
}

int main(int argc,char** argv)
{
    int					log_level = LOG_LEVEL_INFO;

    int                 pack_bytes = 0;
    char			    *log_file = "server.log";
    char                *progname = NULL;
    int                 ch;
    char                *listen_ip = NULL;
	int			        listen_port = 0;   
    int                 daemon_run = 1; 
    long				log_size = 1000*1024;
    sqlite3 		    *db;
	char			    *db_file = "server.db";
    socket_t			sock = {0};
	int                 epoll_fd;
	struct epoll_event  event;
	struct epoll_event  event_array[MAX_EVENTS];
	int					events = 0;
	int 				i;
	int					connect_fd = -1;
    int                 max;
	struct sockaddr_in  client_addr;
	socklen_t			client_addr_len = sizeof(client_addr);
	int					rv = -1;
	char				pack_buf[1024] = {0};
	packet_t			pack = {0};
    struct              pollfd fds_array[1024];
    int                 found;
	char 				buf[1024];
	int					on =1;   
    pid_t             pid;
    struct option opts[]=
    {
        {"ipaddr", required_argument, NULL, 'i'},
        {"port", required_argument, NULL, 'p'},
        {"debug", no_argument, NULL, 'd'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };


    progname = basename(argv[0]);
    while ( -1 != (ch=getopt_long(argc, argv, "i:p:dh", opts, NULL)) )
	{
		switch (ch)
		{
			case 'i':
				listen_ip = optarg;
				break;

			case 'p':
				listen_port = atoi(optarg);
				break;

			case 'd':
				daemon_run = 0;
				log_file = "console";
				log_level = LOG_LEVEL_DEBUG;			
				break;

			case 'h':
				print_usage(progname);
				return 0;

			default:
				return -1;
		}
	}
    if( log_open(log_file, log_level, log_size, THREAD_LOCK_NONE) < 0 )
    {
        fprintf(stderr, "Initial log system failed\n");
        return 1;
    }
  	log_debug("log system open ok\n");
    if (!listen_port)
	{
		print_usage(progname);
		return -3;
	}
	log_debug("Parser arguments ok: IP[%s], PORT[%d], LOG[%s]\n", listen_ip, listen_port, log_file);

    set_socket_rlimit();
    install_signal();

    db_open(&db, db_file);

	db_create(db, TA_CREATE);
    
	if (daemon_run)
	{
		if (daemon(0, 0) < 0)
		{
			log_error("daemon() error: %s\n", strerror(errno));
			return -4;
		}
		else
		{
			log_info("Program running in daemon mode\n");
            log_info("fork mode\n");
		}
	}
    socket_init(&sock, listen_ip, listen_port);
    if (socket_server_init(&sock) < 0)
	{
		log_error("socket_listen() error\n");
		return -5;
	}
    setsockopt(sock.fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	log_debug("Socket listen ok\n");
    while (!g_sigstop)
    {
        log_info("start accept new client incoming..\n");
        if ( (connect_fd=accept(sock.fd, (struct sockaddr *)&client_addr, &client_addr_len)) < 0 )
        {
            log_info("accept new client failure: %s\n", strerror(errno));
            continue;
        }
        log_info("Accept new client[%s:%d] with fd [%d]\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), connect_fd);  
        pid=fork();
        if(pid<0)
        {
            log_info("fork() create child process failure: %s\n", strerror(errno));
            close(connect_fd);
            continue;
        } 
        else if(pid>0)
        {

            close(connect_fd);
            continue;
        }
        else if(0==pid)
        {
            close(sock.fd);
            log_info("Child process start to commuicate with socket client...\n");
            while(1)
            {
                memset(buf,0,sizeof(buf));
                if( (rv=socket_read(connect_fd, buf, sizeof(buf))) <= 0)
                {
                    log_info("socket[%d] read failure or get disconncet.\n", connect_fd);
                    close(connect_fd);
                    exit(0);
                }
                else
                {
                    log_info("Read %d bytes data[%s] from socket[%d] client[%s:%d] ok\n", rv, buf, connect_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                    packet_segmented_unpack(&pack, buf);		
					write_to_db(db, &pack);		
                }

            }
        }
    }
    return 0;
}